package com.miyake.client.datamanage;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.event.logical.shared.SelectionEvent;
import com.google.gwt.event.logical.shared.SelectionHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Tree;
import com.miyake.client.DataService;
import com.miyake.client.DataServiceAsync;

public class DataList extends Composite {
	public interface DataListHandler {
		void onSelectChange(NodeProperty node);
	}
	List<DataListHandler> handlers = new ArrayList<DataListHandler>();
	private void fireSelectChangeEvent(NodeProperty node) {
		for (DataListHandler handler : handlers) {
			handler.onSelectChange(node);
		}
	}
	public void addDataListHandler(DataListHandler handler) {
		handlers.add(handler);
	}
	
	public interface Images extends ClientBundle, Tree.Resources {
		public static final Images INSTANCE =  GWT.create(Images.class);
		ImageResource folder_closed();
		ImageResource folder_open();
		ImageResource icon_doc_sml();
		ImageResource gwtc_calendar();
		ImageResource arrow();
		ImageResource book();
		ImageResource altopen();
		ImageResource altclose();
		ImageResource graph1();
		ImageResource image();
		ImageResource text();
	}
	
	private Tree tree;
	private Images images = GWT.create(Images.class); 
	private DataServiceAsync service = DataService.Util.getInstance();
	private TreeItem activeNode;
	private String defaultNode = null;
	
	public DataList() {
		initialize();
	}
	
	public DataList(String defaultNode) {
		this.defaultNode  = defaultNode;
		initialize();
	}
	
	private void initialize() {
		VerticalPanel verticalPanel = new VerticalPanel();
		initWidget(verticalPanel);
		verticalPanel.setWidth("100px");
		
		tree = new Tree();
		verticalPanel.add(tree);
		tree.setWidth("100%");
		
		tree.addOpenHandler(new OpenHandler<TreeItem>() {
			@Override
			public void onOpen(OpenEvent<TreeItem> event) {

			}
		});
		
		tree.addSelectionHandler(new SelectionHandler<TreeItem>() {
			@Override
			public void onSelection(SelectionEvent<TreeItem> event) {
				activeNode = tree.getSelectedItem();
				fireSelectChangeEvent((NodeProperty)activeNode.getUserObject());
			}	
		});
		
		initRootNodes();
	}

	private void getSubNodes(final TreeItem treeItem) {
		String key = ((NodeProperty)treeItem.getUserObject()).getKey();
		service.getSubNodes(key, new AsyncCallback<List<NodeProperty>>() {
			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(List<NodeProperty> result) {
				if (result != null) {
					List<TreeItem> list = createSubNodes(result);
					for (TreeItem ti : list) {
						treeItem.addItem(ti);
					}
				}
			}		
		});
	}
	
	private String imageItemHTML(ImageResource imageProto, String title) {      
		if (title.length() > 10) {
			title = title.substring(0, 9) + "...";
		}
		return AbstractImagePrototype.create(imageProto).getHTML() + " " + title;    
	}
	
	private String getTreeItemText(NodeProperty np) {
		if (NodeProperty.FOLDER == np.getType()){ 
			return imageItemHTML(images.folder_open(), np.getName());
		}
		else if (NodeProperty.ROOTNODE == np.getType()) {
			return imageItemHTML(images.altclose(), np.getName());
		}
		else if (NodeProperty.DATA == np.getType()) {
			return imageItemHTML(images.icon_doc_sml(), np.getName());
		}
		else if (NodeProperty.PLOT == np.getType()) {
			return imageItemHTML(images.graph1(), np.getName());
		}
		else if (NodeProperty.TABLE == np.getType()) {
			return imageItemHTML(images.gwtc_calendar(), np.getName());
		}
		else if (NodeProperty.PAPER == np.getType()) {
			return imageItemHTML(images.book(), np.getName());
		}
//		else if (NodeProperty.TEXT == np.getType()) {
//			return imageItemHTML(images.text(), np.getName());
//		}
		else if (NodeProperty.IMAGE == np.getType()) {
			return imageItemHTML(images.image(), np.getName());
		}
		else {
			return np.getName();
		}		
	}
	
	private TreeItem createTreeItem(NodeProperty np) {
		return new TreeItem(getTreeItemText(np));
	}
	
	private List<TreeItem> createSubNodes(List<NodeProperty> result) {
		List<TreeItem> ret = new ArrayList<TreeItem>();
		for (NodeProperty np : result) {
			TreeItem treeItem = createTreeItem(np);
			treeItem.setUserObject(np);
			ret.add(treeItem);
			getSubNodes(treeItem);
		}
		return ret;
	}
	
	public void initRootNodes() {
		tree.clear();
		if (isMyData()) {
			getMyNode();
		}
		else {
			getSomeOnesNode();			
		}
	}
	protected void getSomeOnesNode() {
		service.getNode(defaultNode, new AsyncCallback<NodeProperty>() {
			@Override
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}

			@Override
			public void onSuccess(NodeProperty result) {
				TreeItem treeItem = createTreeItem(result);
				treeItem.setUserObject(result);
				tree.addItem(treeItem);
				getSubNodes(treeItem);
			}
		});
	}
	protected void getMyNode() {
		service.getRootNodes("", new AsyncCallback<List<NodeProperty>>() {
			@Override
			public void onFailure(Throwable caught) {
				Window.alert(caught.getMessage());
			}

			@Override
			public void onSuccess(List<NodeProperty> result) {
				List<TreeItem> list = createSubNodes(result);
				for (TreeItem treeItem : list) {
					tree.addItem(treeItem);
				}
			}
		});
	}

	private boolean isMyData() {
		if (this.defaultNode == null) {
			return true;
		}
		return false;
	}
	
	public String getSelectedNodeKey() {
		return ((NodeProperty)activeNode.getUserObject()).getKey();
	}
	
	private void updateNode(final TreeItem treeItem) {
		String key = ((NodeProperty)treeItem.getUserObject()).getKey();
		service.getNode(key, new AsyncCallback<NodeProperty>() {
			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(NodeProperty result) {
				treeItem.setHTML(getTreeItemText(result));
				treeItem.setUserObject(result);
				getSubNodes(treeItem);
				fireSelectChangeEvent((NodeProperty)treeItem.getUserObject());
			}
		});
	}
	
	public void updateNode(String key) {
		TreeItem target = null;
		for (int i = 0; i < tree.getItemCount(); i++) {
			TreeItem item = tree.getItem(i);
			target = findNode(item, key);
			if (target != null) {
				break;
			}
		}
		target.removeItems();
		updateNode(target);
	}
	
	public void updateActiveNode() {
		activeNode.removeItems();
		updateNode(activeNode);
	}
	
	public void updateParentNode() {
		activeNode = activeNode.getParentItem();
		updateActiveNode();
	}
	
	private TreeItem findNode(TreeItem treeItem, String key) {
		NodeProperty prop = (NodeProperty)treeItem.getUserObject();
		if (prop.getKey().equals(key)) {
			return treeItem;
		}
		else {
			for (int i = 0; i < treeItem.getChildCount(); i++) {
				prop = (NodeProperty)treeItem.getChild(i).getUserObject();
				if (prop.getKey().equals(key)) {
					return treeItem.getChild(i);
				}
				else {
					TreeItem treeItem2 = findNode(treeItem.getChild(i), key);
					if (treeItem2 != null) {
						return treeItem2;
					}
				}
			}
		}
		return null;
	}

	public NodeProperty getSelectedNode() {
		return (NodeProperty)activeNode.getUserObject();
	}
	
	public void setSelectedNode(String key) {
		tree.getSelectedItem().setSelected(false);
		TreeItem target = null;
		for (int i = 0; i < tree.getItemCount(); i++) {
			TreeItem item = tree.getItem(i);
			item.setSelected(false);
			target = findNode(item, key);
			if (target != null) {
				break;
			}
		}
		TreeItem item = target.getParentItem();
		while(item != null) {
			item.setState(true);
			item = item.getParentItem();
		}
		
		//target.setSelected(true);
		tree.setSelectedItem(target);
		target.setState(true);
		fireSelectChangeEvent((NodeProperty)target.getUserObject());
	}
	
	public Integer getOrder() {
		return activeNode.getParentItem().getChildIndex(activeNode);
	}
	
	public void updateActiveNodePath() {
		updateActiveNode();
		TreeItem node = activeNode;
		while (true) {
			updateNodeObject(node);
			node = node.getParentItem();
			if (node == null) {
				break;
			}
		}
	}
	
	private void updateNodeObject(final TreeItem node) {
		service.getNode(((NodeProperty)node.getUserObject()).getKey(), new AsyncCallback<NodeProperty>() {
			@Override
			public void onFailure(Throwable caught) {
			}

			@Override
			public void onSuccess(NodeProperty result) {
				node.setUserObject(result);
			}
		});
	}
}
